home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Topik / Topik - Disk 15 - Nifty (19xx)(Topik Public Domain)(PD)[WB].zip / Topik - Disk 15 - Nifty (19xx)(Topik Public Domain)(PD)[WB].adf / Globe / pop.c < prev    next >
C/C++ Source or Header  |  1989-08-07  |  20KB  |  674 lines

  1. /*
  2.  *  The functions for pop-up menus
  3.  *
  4.  *  Written by Derek Zahn (Gambit Software, Madison WI), July 1987
  5.  *
  6.  *  This code is freely distributable and is blessed by its author for
  7.  *  inclusion, in this form or any other, into Amiga programs,
  8.  *  commercial or non-commercial.  If this is done, no credit must be
  9.  *  given to me (although I wouldn't mind).
  10.  *
  11.  *  This code was developed and tested under Manx Aztec C, version 3.40a
  12.  *  with small code, small data, and short integers as part of the Gambit
  13.  *  Software development environment.  It has been "unGambitized" for
  14.  *  general use.  I am unfamiliar with other Amiga C compilers, so cannot
  15.  *  speculate on any porting difficulties.  This file was created with a
  16.  *  text editor (Z) whose tabstops were set to 8, so that it may be easily
  17.  *  and intelligibly printed.  This code was developed under 1.2; I am
  18.  *  not sure if it will work under 1.1, but can't see why not.
  19.  *
  20.  *  Note that there are some features that should be supported but are not,
  21.  *  and some issues about the function and interface that make me nervous.
  22.  *  These are explained in the appendix to the documentation.  I would
  23.  *  greatly appreciate receiving any enhancements and modifications to this
  24.  *  code, or suggestions therefor.  Comments on techniques and coding
  25.  *  style are always appreciated.  Enjoy.
  26.  */
  27.  
  28. /* include files */
  29.  
  30. #include <exec/types.h>
  31. #include <intuition/intuitionbase.h>
  32. #include <intuition/intuition.h>
  33. #include <graphics/gfxmacros.h>
  34. #include "popmenu.h"
  35.  
  36. /* Externally defined functions used in this module */
  37.  
  38. extern struct Window *OpenWindow();
  39. extern struct IntuiMessage *GetMsg(); /* type coercion, true... */
  40. extern VOID CloseWindow(), ReplyMsg(), Wait();
  41. extern VOID RectFill(), Move(), Draw(), Text(), PrintIText(), DrawImage();
  42.  
  43. /* The following functions are defined in this module */
  44.  
  45. extern LONG PopChoose();  /* blocking user interface -- exported */
  46. extern SHORT pop_computestate(); /* see who is selected, if anybody */
  47. extern VOID pop_highlight(); /* highlight the specified item */
  48. extern VOID pop_unhighlight(); /* unhighlight the specified item */
  49. extern VOID pop_do_highlighting(); /* high or un high light the item */
  50. extern VOID pop_render(); /* draws the title (if existent) and menu items */
  51. extern VOID pop_draw_menuitem(); /* draws the menu item */
  52. extern struct MenuItem *pop_getitem(); /* find a MenuItem struc */
  53. extern SHORT pop_strlen(); /* local strlen() */
  54.  
  55. /* This is structure will be used to create a window for display of the    */
  56. /* menu.  In my heart of hearts, I wanted to use graphics library          */
  57. /* functions instead, but reason prevailed.  Note the use of the RMBTRAP   */
  58. /* flag -- while the pop-up menu is being processed, there is no use for   */
  59. /* the right button.  Perhaps this should only be set if the right button  */
  60. /* has some bearing on the pop-up menu.                                    */
  61.  
  62. static
  63. struct NewWindow pop_window = {
  64.     0, 0, /* LeftEdge, TopEdge: will be filled in later */
  65.     0, 0, /* Width, Height: will be filled in later */
  66.     (UBYTE) -1, (UBYTE) -1, /* BlockPen, DetailPen */
  67.     MOUSEBUTTONS | MOUSEMOVE, /* IDCMP flags */
  68.     SMART_REFRESH | REPORTMOUSE | ACTIVATE | RMBTRAP, /* flags */
  69.     NULL, /* no gadgets */
  70.     NULL, /* checkmark inherited later */
  71.     NULL, /* no title */
  72.     NULL, /* Screen -- will be filled in later */
  73.     NULL, /* No custom bitmap */
  74.     0, 0, /* MinWidth, MinHeight -- no change in size necessary */
  75.     0, 0, /* MaxWidth, MaxHeight -- no change in size necessary */
  76.     CUSTOMSCREEN /* always use this value */
  77. };
  78.  
  79. /* It is assumed that the following point to bases of opened libraries     */
  80.  
  81. extern struct IntuitionBase *IntuitionBase;
  82. extern struct GfxBase *GfxBase;
  83.  
  84. /*
  85.  * PopChoose(menu, win)
  86.  * menu -- pointer to the menu to pop
  87.  * win -- the window to which this menu relates.  NULL means the currently
  88.  * active window.
  89.  *
  90.  * This function provides a blocking pop-up menu.  It returns (LONG) -1 if 
  91.  * either an error occurred attempting to pop or if no selection was made
  92.  * by the user.  If a selection was made, a LONG between 0 and n-1, where
  93.  * n is the number of Menu Items.
  94.  *
  95.  * -1 is also returned if a selection of a checked item was made.
  96.  *
  97.  * Since this code opens a window, it is up to the caller to be sure that
  98.  * no scribbling in droll ways is done while this code is in progress.
  99.  */
  100.  
  101. LONG
  102. PopChoose(menu, win)
  103. struct Menu *menu;
  104. struct Window *win;
  105. {
  106.     struct Screen *screen; /* the window's screen */
  107.     struct Window *popwin; /* the pop-up menu */
  108.     struct IntuiMessage *message; /* our eyes and ears */
  109.     struct MenuItem *sel_item; /* the selected item */
  110.     SHORT pop_state, pop_newstate; /* menu selection state varaibles   */
  111.     SHORT mouse_moved; /* keeps track of whether the mouse has moved   */
  112.     SHORT finished; /* set when menu should be blown away */
  113.     SHORT class; /* incoming IntuiMessage class */
  114.     SHORT code; /* incoming IntuiMessage code */
  115.     ULONG exclude; /* for handling mutual exclusion */
  116.  
  117.     /* Check to see that IntuitionBase and GfxBase are non-null.       */
  118.     /* While this is not any sort of guarantee against disaster, it    */
  119.     /* is better than nothing.                                         */
  120.  
  121.     if((IntuitionBase == NULL) || (GfxBase == NULL))
  122.         return((LONG) (-1));
  123.  
  124.     /* One paranoid check */
  125.  
  126.     if(menu == NULL)
  127.         return((LONG) (-1));
  128.  
  129.     /* If the menu is not MENUENABLED, nothing to do                   */
  130.  
  131.     if(!(menu->Flags & MENUENABLED))
  132.         return((LONG) (-1));
  133.  
  134.     /* Form the menu window to blast forth into the Visual World. Note */
  135.     /* the unconventional (and inconsistent with Intuition) ways that  */
  136.     /* the Width and Height fields are used here.                      */
  137.  
  138.     pop_window.Width = menu->Width;
  139.     pop_window.Height = menu->Height;
  140.  
  141.     if(win == NULL)
  142.         win = IntuitionBase->ActiveWindow;
  143.     if(win == NULL) /* panic */
  144.         return((LONG) (-1));
  145.  
  146.     /* Inherit CheckMark from the "parent" window                      */
  147.  
  148.     if(win->CheckMark)
  149.         pop_window.CheckMark = win->CheckMark;
  150.  
  151.     screen = win->WScreen;
  152.     pop_window.Screen = screen;
  153.  
  154.     pop_window.LeftEdge = menu->LeftEdge;
  155.     pop_window.TopEdge = menu->TopEdge;
  156.  
  157.     /* if we are supposed to return to the last-selected menu item and */
  158.     /* such a beast exists, all other positioning information (except  */
  159.     /* POPTIDY) will be circumvented.  The menu will appear under the  */
  160.     /* pointer with the last-chosen item pre-selected, if this is      */
  161.     /* possible given the POPTIDY flag and the screen constraints.     */
  162.     /* In this case, the LeftEdge and TopEdge fields of the menu       */
  163.     /* structure will have been altered (I know, ick!) to provide a    */
  164.     /* relative offset with respect to the pointer to do the deed      */
  165.  
  166.     if((menu->Flags & POPREMEMBER) && (menu->Flags & POPUSED)) {
  167.         pop_window.LeftEdge += screen->MouseX;
  168.         pop_window.TopEdge += screen->MouseY;
  169.     }
  170.     else {
  171.         if(menu->Flags & POPPOINTREL) {
  172.             pop_window.LeftEdge += screen->MouseX;
  173.             pop_window.TopEdge += screen->MouseY;
  174.         }
  175.         else if(menu->Flags & POPWINREL) {
  176.             pop_window.LeftEdge += win->LeftEdge;
  177.             pop_window.TopEdge += win->TopEdge;
  178.         }
  179.     }
  180.  
  181.     /* If the caller wishes us to be POPTIDY, the menu must completely */
  182.     /* appear on the screen, whatever other effects this may have on   */
  183.     /* menu positioning.  The left edge and top edge must be altered   */
  184.     /* accordingly.  In the pathological case where the menu is larger */
  185.     /* than the screen, -1 is returned.                                */
  186.     /* If poptidiness is not a factor, the size of the window may have */
  187.     /* to be altered if it shoots off the bottom or right edge of the  */
  188.     /* screen.  There should be some similar mechanism to deal with    */
  189.     /* the menu if it extends past the top or left edge of the screen; */
  190.     /* as it stands now, the OpenWindow() call will fail, and the      */
  191.     /* result may be even more dire under 1.1.  Use 1.2!               */
  192.  
  193.     if(menu->Flags & POPTIDY) {
  194.         if((pop_window.Width > screen->Width) || 
  195.            (pop_window.Height > screen->Height))
  196.                return((LONG) (-1));
  197.         if(pop_window.LeftEdge + pop_window.Width > screen->Width)
  198.             pop_window.LeftEdge = screen->Width-pop_window.Width;
  199.         if(pop_window.TopEdge + pop_window.Height > screen->Height)
  200.             pop_window.TopEdge=screen->Height-pop_window.Height;
  201.         if(pop_window.LeftEdge < screen->LeftEdge)
  202.             pop_window.LeftEdge = screen->LeftEdge;
  203.         if(pop_window.TopEdge < screen->TopEdge)
  204.             pop_window.TopEdge = screen->TopEdge;
  205.     }
  206.     else {
  207.         if(pop_window.LeftEdge + pop_window.Width > screen->Width)
  208.             pop_window.Width = screen->Width - 
  209.               pop_window.LeftEdge;
  210.         if(pop_window.TopEdge + pop_window.Height > screen->Height)
  211.             pop_window.Height = screen->Height -
  212.               pop_window.TopEdge;
  213.     }
  214.  
  215.     /* There!  Finally, the window is ready to be displayed!  First,   */
  216.     /* create it.                                                      */
  217.  
  218.     popwin = OpenWindow(&pop_window);
  219.     if(popwin == NULL) /* all that work for nuthin' */
  220.         return((LONG) (-1));
  221.  
  222.     /* Now, render the menu items and (possibly) the menu title.       */
  223.  
  224.     pop_render(popwin, menu);
  225.  
  226.     /* Now, see if the pointer is over a selection.  The variable      */
  227.     /* 'pop_state' will from this point on hold the value, in linear   */
  228.     /* traversal order of the MenuItems (zero-indexed), the currently  */
  229.     /* selected menu item, or -1 if none are selected.                 */
  230.  
  231.     pop_state = pop_computestate(popwin, menu);
  232.  
  233.     /* If one is indeed currently selected, highlight it.              */
  234.  
  235.     if(pop_state >= 0)
  236.         pop_highlight(popwin, menu, pop_state);
  237.  
  238.     /* Here is the IDCMP loop that will process the pop-up menu.  Note */
  239.     /* that on mousemove events, I don't care where it moved, just if  */
  240.     /* it did -- pop_computestate() will figure out where by reaching  */
  241.     /* into the Window structure.  Not Pure Programming, somehow, but  */
  242.     /* blessed by the Intuition manual.                                */
  243.  
  244.     finished = 0;
  245.     while(1) {
  246.         mouse_moved = 0;
  247.         Wait((ULONG) 1L << popwin->UserPort->mp_SigBit);
  248.         while(message = GetMsg(popwin->UserPort)) {
  249.             class = message->Class;
  250.             code = message->Code;
  251.             ReplyMsg(message);
  252.  
  253.             /* The only messages we should be getting are      */
  254.             /* mouse button and move events.  Button events    */
  255.             /* could signify the end of this routine's         */
  256.             /* epheremal spotlight role.                       */
  257.  
  258.             switch(class) {
  259.               case MOUSEMOVE:
  260.                   mouse_moved = 1;
  261.                 break;
  262.               case MOUSEBUTTONS:
  263.                   switch(code) {
  264.                   case SELECTDOWN:
  265.                       if((menu->Flags & POPLEFTBUTTON) &&
  266.                        (menu->Flags & POPTRIGGERDOWN))
  267.                            finished = 1;
  268.                     break;
  269.                   case SELECTUP:
  270.                       if((menu->Flags & POPLEFTBUTTON) &&
  271.                        (menu->Flags & POPTRIGGERUP))
  272.                            finished = 1;
  273.                     break;
  274.                   case MENUDOWN:
  275.                       if((menu->Flags & POPRIGHTBUTTON) &&
  276.                        (menu->Flags & POPTRIGGERDOWN))
  277.                            finished = 1;
  278.                     break;
  279.                   case MENUUP:
  280.                       if((menu->Flags & POPRIGHTBUTTON) &&
  281.                        (menu->Flags & POPTRIGGERUP))
  282.                            finished = 1;
  283.                     break;
  284.                   default: /* huh? */
  285.                       break;
  286.                 }
  287.                 break;
  288.               default: /* huh? */
  289.                   break;
  290.             }
  291.         }
  292.  
  293.         /* if the exit conditions have been met, we can return our */
  294.         /* results with honor and dignity, having served.          */
  295.         /* Note that if we are remembering the last selection, the */
  296.         /* menu structure is mangled to make that possible.        */
  297.  
  298.         if(finished) {
  299.             pop_state = pop_computestate(popwin, menu);
  300.             if(pop_state >= 0) {
  301.                 if(menu->Flags & POPREMEMBER) {
  302.                     menu->Flags |= POPUSED;
  303.                     menu->LeftEdge = -1 * popwin->MouseX;
  304.                     menu->TopEdge =  -1 * popwin->MouseY;
  305.                 }
  306.  
  307.                 /* Special things to do if the menu entry  */
  308.                 /* is of type CHECKIT                      */
  309.  
  310.                 sel_item = pop_getitem(menu, pop_state);
  311.                 if(sel_item->Flags & CHECKIT) {
  312.                   if(sel_item->Flags & CHECKED) {
  313.                     pop_state = -1;
  314.                     if(sel_item->Flags & MENUTOGGLE)
  315.                       sel_item->Flags &= ~CHECKED;
  316.                   }
  317.                   else {
  318.                     sel_item->Flags |= CHECKED;
  319.  
  320.                     /* Handle mutual exclusion */
  321.  
  322.                     exclude = sel_item->MutualExclude;
  323.                     if(exclude) {
  324.                       sel_item = menu->FirstItem;
  325.                       while(sel_item) {
  326.                         if(exclude & 1)
  327.                           sel_item->Flags &= ~CHECKED;
  328.                         exclude >>= 1;
  329.                         sel_item = sel_item->NextItem;
  330.                       }
  331.                     }
  332.                   }
  333.                 }
  334.             }
  335.             CloseWindow(popwin);
  336.             return((LONG) pop_state);
  337.         }
  338.  
  339.         /* if the mouse has moved, find out its new state and      */
  340.         /* alter the highlighting accordingly.                     */
  341.  
  342.         if(mouse_moved) {
  343.             pop_newstate = pop_computestate(popwin, menu);
  344.             if(pop_newstate != pop_state) {
  345.                 if(pop_state >= 0)
  346.                     pop_unhighlight(popwin,
  347.                       menu, pop_state);
  348.                 if(pop_newstate >= 0)
  349.                     pop_highlight(popwin, 
  350.                       menu, pop_newstate);
  351.                 pop_state = pop_newstate;
  352.             }
  353.         }
  354.     }
  355. }
  356.  
  357. /*
  358.  * pop_computestate()
  359.  *
  360.  * This function checks to see where the mouse pointer is in relation to
  361.  * the various menu items in the menu.  If it is inside one of them, it
  362.  * returns which one (indexed by its linear position in the MenuItem list
  363.  * with 0 being the first one).  If not, returns -1.
  364.  *
  365.  * Possible future enhancement: keep a set of state variables containing
  366.  * the UL and LR corners of the last-known select box; this would make
  367.  * a quick check possible and would cut down the computation for short
  368.  * mouse movements (the most common).
  369.  */
  370.  
  371. static SHORT
  372. pop_computestate(win, menu)
  373. struct Window *win;
  374. struct Menu *menu;
  375. {
  376.     register SHORT current = 0;
  377.     register SHORT xval, yval;
  378.     register struct MenuItem *item;
  379.  
  380.     /* Get the x and y vals of the mouse position */
  381.  
  382.     xval = win->MouseX;
  383.     yval = win->MouseY;
  384.  
  385.     /* If there is a title, decrement the yval by the correct amount */
  386.  
  387.     if(menu->MenuName)
  388.         yval -= POPTITLEHEIGHT;
  389.  
  390.     /* First, see if the pointer is even in the window */
  391.  
  392.     if((xval < 0) || (yval < 0) ||
  393.        (xval > win->Width) || (yval > win->Height))
  394.            return(-1);
  395.  
  396.     /* search through the list of menu items, checking the select box  */
  397.     /* of each.  If containment is detected, the job is done.          */
  398.  
  399.     item = menu->FirstItem;
  400.     while(item) {
  401.         if((xval >= item->LeftEdge) && (yval >= item->TopEdge) &&
  402.            (xval <= item->LeftEdge + item->Width) &&
  403.            (yval <= item->TopEdge + item->Height)) {
  404.  
  405.                /* We have found the quarry; now, the result only  */
  406.             /* depends on the MenuItem's ITEMENABLED flag.     */
  407.  
  408.             if(item->Flags & ITEMENABLED)
  409.                    return(current);
  410.             else
  411.                 return(-1);
  412.         }
  413.         current++;
  414.         item = item->NextItem;
  415.     }
  416.  
  417.     /* If the list is exhausted, return the sad news */
  418.  
  419.     return(-1);
  420. }
  421.  
  422. /*
  423.  * pop_highlight()
  424.  *
  425.  * highlight a menu item
  426.  */
  427.  
  428. static VOID
  429. pop_highlight(win, menu, state)
  430. struct Window *win;
  431. struct Menu *menu;
  432. SHORT state;
  433. {
  434.     pop_do_highlighting(win, menu, state, 0);
  435. }
  436.  
  437. /*
  438.  * pop_unhighlight()
  439.  *
  440.  * unhighlight a menu item
  441.  */
  442.  
  443. static VOID
  444. pop_unhighlight(win, menu, state)
  445. struct Window *win;
  446. struct Menu *menu;
  447. SHORT state;
  448. {
  449.     pop_do_highlighting(win, menu, state, 1);
  450. }
  451.  
  452. /*
  453.  * pop_do_highlighting()
  454.  *
  455.  * Highlight or unhighlight a menu item, given its traversal number.  Assumes
  456.  * this is a rational value -- if it isn't, Watch Out.
  457.  */
  458.  
  459. static VOID
  460. pop_do_highlighting(win, menu, state, mode)
  461. struct Window *win;
  462. struct Menu *menu;
  463. SHORT state;
  464. SHORT mode; /* 0 means to highlight, 1 means to unhighlight */
  465. {
  466.     register struct MenuItem *item;
  467.     struct RastPort *rp;
  468.     SHORT offset = 0;
  469.  
  470.     if(menu->MenuName)
  471.         offset = POPTITLEHEIGHT;
  472.  
  473.     /* Get the correct MenuItem structure */
  474.  
  475.     item = pop_getitem(menu, state);
  476.  
  477.     rp = win->RPort;
  478.  
  479.     /* Now, do the highlighting!  The action to be taken depends on    */
  480.     /* the type of highlighting desired for this item.                 */
  481.     /* The way that the flags for highlighting works is truly bizarre  */
  482.  
  483.     if((item->Flags & HIGHNONE) == HIGHNONE)
  484.         return;
  485.  
  486.     if(item->Flags & HIGHCOMP) {
  487.         SetDrMd(rp, COMPLEMENT);
  488.         RectFill(rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  489.           offset), (LONG) (item->LeftEdge + item->Width - 1),
  490.           (LONG) (item->TopEdge + item->Height + offset));
  491.     }
  492.     else if(item->Flags & HIGHBOX) {
  493.         SetDrMd(rp, COMPLEMENT);
  494.         Move(rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge + 
  495.           offset));
  496.         Draw(rp, (LONG) (item->LeftEdge + item->Width - 1),
  497.           (LONG) (item->TopEdge + offset));
  498.         Draw(rp, (LONG) (item->LeftEdge + item->Width - 1),
  499.           (LONG) (item->TopEdge + item->Height + offset));
  500.         Draw(rp, (LONG) item->LeftEdge,
  501.           (LONG) (item->TopEdge + item->Height + offset));
  502.         Draw(rp, (LONG) item->LeftEdge, (LONG) 
  503.           (item->TopEdge + offset));
  504.     }
  505.  
  506.     /*  Otherwise, the mode is HIGHIMAGE */
  507.  
  508.     else
  509.         pop_draw_menuitem(win, item, !mode, offset);
  510. }
  511.  
  512. /*
  513.  * pop_render()
  514.  *
  515.  * renders the menu title (if existent) and the menu items
  516.  */
  517.  
  518. static VOID
  519. pop_render(win, menu)
  520. struct Window *win;
  521. struct Menu *menu;
  522. {
  523.     struct MenuItem *item;
  524.     struct RastPort *rp;
  525.     SHORT offset = 0;
  526.  
  527.     rp = win->RPort;
  528.  
  529.     /* Fill the background with color 1, like Intuition Menus */
  530.  
  531.     SetAPen(rp, 1L);
  532.     RectFill(rp, 0L, 0L, (LONG) win->Width, (LONG) win->Height);
  533.  
  534.     /* First, if there is a Title for this menu, render it in the top */
  535.     /* of the menu.                                                   */
  536.  
  537.     if(menu->MenuName) {
  538.         SetDrMd(rp, JAM1);
  539.         SetAPen(rp, 0L);
  540.         SetBPen(rp, 1L);
  541.         Move(rp, 4L, 7L);
  542.         Text(rp, menu->MenuName, (LONG) pop_strlen(menu->MenuName));
  543.         SetDrMd(rp, COMPLEMENT);
  544.         RectFill(rp,0L,0L, (LONG) win->Width, (LONG) POPTITLEHEIGHT);
  545.         SetDrMd(rp, JAM1);
  546.         offset = POPTITLEHEIGHT;
  547.     }
  548.  
  549.     /* now render all of the menu items */
  550.  
  551.     item = menu->FirstItem;
  552.     while(item) {
  553.         pop_draw_menuitem(win, item, 0, offset);
  554.         item = item->NextItem;
  555.     }
  556. }
  557.  
  558. /* Area fill patterns */
  559.  
  560. static USHORT pop_ghost_pattern[] = {
  561.     0x1111, 0x4444
  562. };
  563. static USHORT pop_normal_pattern[] = {
  564.     0xffff, 0xffff
  565. };
  566.  
  567. /*
  568.  * pop_draw_menuitem()
  569.  *
  570.  * Draws the specified menuitem in the given rastport.  The mode argument
  571.  * says what to draw -- 0 means draw the ItemFill, 1 the SelectFill.
  572.  */
  573.  
  574. static VOID
  575. pop_draw_menuitem(win, item, mode, offset)
  576. struct Window *win;
  577. struct MenuItem *item;
  578. SHORT mode;
  579. SHORT offset;
  580. {
  581.     APTR fill;
  582.     struct RastPort *rp;
  583.  
  584.     /* first, figure out what to do, and return if it is a NULL thing */
  585.  
  586.     if(!mode)
  587.         fill = item->ItemFill;
  588.     else
  589.         fill = item->SelectFill;
  590.  
  591.     if(!fill)
  592.         return;
  593.  
  594.     rp = win->RPort;
  595.  
  596.     /* First, erase what may already be there, just to be sure that    */
  597.     /* everything works out all right.                                 */
  598.  
  599.     SetAPen(rp, 1L);
  600.     SetDrMd(rp, JAM1);
  601.     RectFill(rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  602.       offset), (LONG) (item->LeftEdge + item->Width), (LONG)
  603.       (item->TopEdge + item->Height + offset));
  604.  
  605.     /* If the item is checkmarked, draw the checkmark.  Intuition made */
  606.     /* sure that the CheckMark field of the window structure exists    */
  607.  
  608.     if(item->Flags & CHECKIT)
  609.         if(item->Flags & CHECKED)
  610.             DrawImage(rp, win->CheckMark, (LONG)  item->LeftEdge,
  611.               (LONG) (item->TopEdge + offset + 1));
  612.  
  613.     /* Now, draw the item itself -- depending on the Flag value, it    */
  614.     /* could be either an Image or an IntuiText                        */
  615.  
  616.     if(item->Flags & ITEMTEXT)
  617.         PrintIText(rp, fill, (LONG) item->LeftEdge, 
  618.           (LONG) (item->TopEdge + offset));
  619.     else
  620.         DrawImage(rp, fill, (LONG) item->LeftEdge, 
  621.           (LONG) (item->TopEdge + offset));
  622.  
  623.     /* If the ITEMENABLED flag is not set, "ghost" the item.           */
  624.  
  625.     if(!(item->Flags & ITEMENABLED)) {
  626.         SetAPen(rp, 1L);
  627.         SetDrMd(rp, JAM1);
  628.         SetAfPt(rp, (USHORT *) pop_ghost_pattern, 1L);
  629.         RectFill(rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  630.           offset), (LONG) (item->LeftEdge + item->Width), (LONG)
  631.           (item->TopEdge + item->Height + offset));
  632.         SetAfPt(rp, (USHORT *) pop_normal_pattern, 1L);
  633.     }
  634. }
  635.  
  636. /*
  637.  * pop_getitem()
  638.  *
  639.  * given the traversal number of a menu item in a menu (assumes, BTW, that
  640.  * the arguments are valid), return a pointer to the MenuItem structure
  641.  */
  642.  
  643. static struct MenuItem *
  644. pop_getitem(menu, which)
  645. struct Menu *menu;
  646. SHORT which;
  647. {
  648.     struct MenuItem *item;
  649.  
  650.     item = menu->FirstItem;
  651.     while(which--)
  652.         item = item->NextItem;
  653.     return(item);
  654. }
  655.  
  656. /*
  657.  * pop_strlen()
  658.  *
  659.  * a home-brewed strlen to prevent it being necessary to hook in whatever
  660.  * huge object file in which the c library's strlen() resides.
  661.  */
  662.  
  663. static SHORT
  664. pop_strlen(str)
  665. char *str;
  666. {
  667.     register SHORT count = 0;
  668.  
  669.     for(; *str++; count++);
  670.     return(count);
  671. }
  672.  
  673. /* :-) */
  674.